package com.monkey.log;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

/**
 * @Description: 日志记录切面
 * https://blog.csdn.net/lhj520cb/article/details/125820513?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172066235816800188536202%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=172066235816800188536202&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-2-125820513-null-null.142^v100^pc_search_result_base7&utm_term=aop&spm=1018.2226.3001.4187
 *
 * @Author: zhangqi
*/
@Slf4j
@Component
@Aspect//定义切面类 Spring 框架会自动收集这些 Bean, 并添加到 Spring AOP中，使用该注解会被排除在 auto-proxying（自动代理） 机制之外
@ConditionalOnProperty(name = {"log.aspect.enable"},havingValue = "true",matchIfMissing = true)
public class LogAspect {

    //定义切入点 需要增强的地方。实际被真正增强的方法，称为切入点
    //execution格式 （【权限修饰符】【返回类型】【类全路径】【方法名称】(【参数列表】)）
    @Pointcut("execution(* com.monkey.*.controller.*Controller.*(..)) || execution(* com.monkey.*.service.*Service.*(..))")
    private void pointCut(){
    }

    /*
        @Around：环绕增强，相当于MethodInterceptor
        @AfterReturning：后置增强，相当于AfterReturningAdvice，方法正常退出时执行
        @Before：标识一个前置增强方法，相当于BeforeAdvice的功能，相似功能的还有
        @AfterThrowing：异常抛出增强，相当于ThrowsAdvice
        @After: final增强，不管是抛出异常或者正常退出都会执行
     */
    //环绕通知=前置+目标方法执行+后置通知，proceed方法就是用于启动目标方法执行的

    /**
     * 环绕增强，增强切点所在的方法
     */
    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //获取参数
        Object[] reqArgs = pjp.getArgs();
        String req = new Gson().toJson(reqArgs);
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        //获取方法的全路径名称
        String methodName = methodSignature.getDeclaringType().getName() + "." + methodSignature.getName();
        log.info("{},req:{}", methodName, req);
        Long startTime = System.currentTimeMillis();
        //执行方法
        Object responseObj = pjp.proceed();
        String resp = new Gson().toJson(responseObj);
        Long endTime = System.currentTimeMillis();
        log.info("{},response:{},costTime:{}", methodName, resp, endTime - startTime);
        return responseObj;
    }


}
